#include "MemPool.h"

#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "utils/acelog.h"
struct MemPool pool;
struct MemPool slave_pool[64];

#ifdef ACEMESH_SCHEDULER_PROFILING
unsigned long mempool_alloc_block_num = 0;
extern int my_mpi_rank;
#endif
struct block *mempool_allocblock(struct MemPool pool)
{
#ifdef TARG_SW5
    struct block *myblock = (struct block *)malloc(sizeof(struct block));
    myblock->data = malloc(UNITSIZE);
#elif TARG_SW9
    struct block *myblock = (struct block *)libc_uncached_aligned_malloc(sizeof(struct block));
    myblock->data = (void *)libc_uncached_aligned_malloc(UNITSIZE);
#ifdef ACEMESH_SCHEDULER_PROFILING
    if (my_mpi_rank <= 0)
        printf("my_block_addr=%p, myblock_data_addr=%p\n", myblock, myblock->data);
#endif
#endif
#ifdef ACEMESH_SCHEDULER_PROFILING
    mempool_alloc_block_num++;
#endif

    myblock->next = NULL;
    return myblock;
}
void InitPool()
{
    alog_debug("InitPool");
    pool.EndBlock = NULL;
    pool.AllocatedMemBlock = NULL;
    pool.FreeMemBlock = NULL;
    pool.self1 = NULL;

    pool.FreeMemBlock = mempool_allocblock(pool);
    //    void *s=memset(((char *)pool.MemBlock+sizeof(struct Unit)),0, pool.UnitSize);
    pool.EndBlock = (void *)((char *)(pool.FreeMemBlock->data) + UNITSIZE);
    //printf("*********%dmaster_InitPool%d\n",(char *)(pool.FreeMemBlock->data),(char *)(pool.FreeMemBlock->data) + UNITSIZE);

    pool.self1 = (void *)(pool.FreeMemBlock->data);
    struct block *pCurUnit = pool.FreeMemBlock;
    pool.FreeMemBlock = pool.FreeMemBlock->next;
    pCurUnit->next = pool.AllocatedMemBlock;
    pool.AllocatedMemBlock = pCurUnit;
}
void slave_initpool()
{
    for (int i = 0; i < 64; i++) {
        slave_pool[i].EndBlock = NULL;
        slave_pool[i].AllocatedMemBlock = NULL;
        slave_pool[i].FreeMemBlock = NULL;
        slave_pool[i].self1 = NULL;

        slave_pool[i].FreeMemBlock = mempool_allocblock(slave_pool[i]);
        //    void *s=memset(((char *)pool.MemBlock+sizeof(struct Unit)),0, pool.UnitSize);
        slave_pool[i].EndBlock = (void *)((char *)(slave_pool[i].FreeMemBlock->data) + UNITSIZE);
         //printf("*********%dslave_InitPool%d\n",(char *)(slave_pool[i].FreeMemBlock->data),(char *)(slave_pool[i].FreeMemBlock->data) + UNITSIZE);
        slave_pool[i].self1 = (void *)(slave_pool[i].FreeMemBlock->data);
        struct block *pCurUnit = slave_pool[i].FreeMemBlock;
        slave_pool[i].FreeMemBlock = slave_pool[i].FreeMemBlock->next;
        pCurUnit->next = slave_pool[i].AllocatedMemBlock;
        slave_pool[i].AllocatedMemBlock = pCurUnit;
    }
}
void *acemesh_myalloc_aligned_4(int datasize)
{
    if ((long long)pool.self1 % 4 > 0)
        pool.self1 = (void *)((char *)pool.self1 + (4 - (long long)pool.self1 % 4));
    if (((char *)pool.EndBlock - (char *)pool.self1) < datasize) {
        if (pool.FreeMemBlock == NULL) {
            pool.FreeMemBlock = mempool_allocblock(pool);
        }
        struct block *pCurUnit = pool.FreeMemBlock;
        pool.FreeMemBlock = pool.FreeMemBlock->next;
        pCurUnit->next = pool.AllocatedMemBlock;
        pool.AllocatedMemBlock = pCurUnit;
        pool.EndBlock = (void *)((char *)(pCurUnit->data) + UNITSIZE);
        pool.self1 = (void *)(pCurUnit->data);
    }
    void *self = (void *)pool.self1;
    pool.self1 = (void *)((char *)pool.self1 + datasize);
    return (void *)self;
}
void *acemesh_myalloc_aligned_8(int datasize)
{
    if ((long long)pool.self1 % 8 > 0)
        pool.self1 = (void *)((char *)pool.self1 + (8 - (long long)pool.self1 % 8));

    if (((char *)pool.EndBlock - (char *)pool.self1) < datasize) {
        if (pool.FreeMemBlock == NULL) {
            pool.FreeMemBlock = mempool_allocblock(pool);
        }
        struct block *pCurUnit = pool.FreeMemBlock;
        pool.FreeMemBlock = pool.FreeMemBlock->next;
        pCurUnit->next = pool.AllocatedMemBlock;
        pool.AllocatedMemBlock = pCurUnit;
        pool.EndBlock = (void *)((char *)(pCurUnit->data) + UNITSIZE);
        pool.self1 = (void *)(pCurUnit->data);
    }
    void *self = (void *)pool.self1;
    pool.self1 = (void *)((char *)pool.self1 + datasize);
    return (void *)self;
}

void *acemesh_myalloc_aligned_16(int datasize)
{
    alog_debug("pool.self1: %x", pool.self1);
    // self1 point to head of free mem.
    if ((long long)pool.self1 % 16 > 0)
        pool.self1 = (void *)((char *)pool.self1 + (16 - (long long)pool.self1 % 16));
    // after align
    alog_debug("after aligned pool.self1: %x", pool.self1);
    if (((char *)pool.EndBlock - (char *)pool.self1) < datasize) {
        alog_debug("require more mem");
        if (pool.FreeMemBlock == NULL) {
            pool.FreeMemBlock = mempool_allocblock(pool);
        }
        struct block *pCurUnit = pool.FreeMemBlock;
        pool.FreeMemBlock = pool.FreeMemBlock->next;
        pCurUnit->next = pool.AllocatedMemBlock;
        pool.AllocatedMemBlock = pCurUnit;
        pool.EndBlock = (void *)((char *)(pCurUnit->data) + UNITSIZE);
        pool.self1 = (void *)(pCurUnit->data);
    }
    void *self = (void *)pool.self1;
    pool.self1 = (void *)((char *)pool.self1 + datasize);
    alog_debug("after alloc pool.self1: %x", pool.self1);
    alog_debug("new alloc mem: %x", self);
    return (void *)self;
}
void *acemesh_myalloc_aligned_32(int datasize)
{
    if ((long long)pool.self1 % 32 > 0)
        pool.self1 = (void *)((char *)pool.self1 + (32 - (long long)pool.self1 % 32));
    if (((char *)pool.EndBlock - (char *)pool.self1) < datasize) {
        if (pool.FreeMemBlock == NULL) {
            pool.FreeMemBlock = mempool_allocblock(pool);
        }
        struct block *pCurUnit = pool.FreeMemBlock;
        pool.FreeMemBlock = pool.FreeMemBlock->next;
        pCurUnit->next = pool.AllocatedMemBlock;
        pool.AllocatedMemBlock = pCurUnit;
        pool.EndBlock = (void *)((char *)(pCurUnit->data) + UNITSIZE);
        pool.self1 = (void *)(pCurUnit->data);
    }
    void *self = (void *)pool.self1;
    pool.self1 = (void *)((char *)pool.self1 + datasize);
    return (void *)self;
}
void *acemesh_myalloc_aligned_64(int datasize)
{
    if ((long long)pool.self1 % 64 > 0)
        pool.self1 = (void *)((char *)pool.self1 + (64 - (long long)pool.self1 % 64));
    if (((char *)pool.EndBlock - (char *)pool.self1) < datasize) {
        if (pool.FreeMemBlock == NULL) {
            pool.FreeMemBlock = mempool_allocblock(pool);
        }
        struct block *pCurUnit = pool.FreeMemBlock;
        pool.FreeMemBlock = pool.FreeMemBlock->next;
        pCurUnit->next = pool.AllocatedMemBlock;
        pool.AllocatedMemBlock = pCurUnit;
        pool.EndBlock = (void *)((char *)(pCurUnit->data) + UNITSIZE);
        pool.self1 = (void *)(pCurUnit->data);
    }
    void *self = (void *)pool.self1;
    pool.self1 = (void *)((char *)pool.self1 + datasize);
    return (void *)self;
}
void ReInitial()
{
    alog_debug("ReInitialPool");
    while (pool.AllocatedMemBlock != NULL) {
        struct block *pCurUnit = pool.AllocatedMemBlock;
        // void* s=memset(((char *)pool.AllocatedMemBlock+sizeof(struct Unit)),0, pool.UnitSize);
        pool.AllocatedMemBlock = pool.AllocatedMemBlock->next;
        pCurUnit->next = pool.FreeMemBlock;
        pool.FreeMemBlock = pCurUnit;
    }
    pool.self1 = (void *)(pool.FreeMemBlock->data);
    pool.EndBlock = (void *)((char *)(pool.FreeMemBlock->data) + UNITSIZE);
    struct block *pCurUnit = pool.FreeMemBlock;
    pool.FreeMemBlock = pool.FreeMemBlock->next;
    pCurUnit->next = pool.AllocatedMemBlock;
    pool.AllocatedMemBlock = pCurUnit;
}

void FreePool()
{
    alog_debug("FreePool");
    while (pool.FreeMemBlock != NULL) {
        struct block *pCurUnit = pool.FreeMemBlock;
        pool.FreeMemBlock = pool.FreeMemBlock->next;
#ifdef TARG_SW5
        free(pCurUnit->data);
        free(pCurUnit);
#elif TARG_SW9
        libc_uncached_aligned_free(pCurUnit->data);
        libc_uncached_aligned_free(pCurUnit);
#else
        printf("mempool hasn't free\n");
#endif
    }
}
#ifdef TARG_SW9
void *my_malloc_aligned(int size)
{
    if (size <= 0) return NULL;
    //    printf("%d",size);
    //    fflush(stdout);
    void *self = libc_uncached_aligned_malloc(size);
    //    printf(",\t");
    //    fflush(stdout);
    return self;
}
void my_free_aligned(void *self) { libc_uncached_aligned_free(self); }
#endif
